package com.example.yc_plugin_learn;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.StandardMessageCodec;
/**
 * 本插件项目主要演示以下几个方面，主要用于教学使用
 * 1。flutter与原生互相传递事件信息
 * 2。在原生项目中使用第三方包glide加载图片，主要用于演示如何在插件中使用第三方包
 * 3。flutter页面上嵌入原生view，并实现独立的事件互传
 * 4。如何在插件代码里获取当前Context
 * 5。插件开发中Android代码报红的解决
 *
 */

/** YcPluginLearnPlugin */
public class YcPluginLearnPlugin implements FlutterPlugin, MethodCallHandler , ActivityAware {

  /**
   * 通道，用来收flutter消息
   */
  private MethodChannel channel;

  /**
   * 事件通道，用来发消息给flutter
   */
  private EventChannel.EventSink sink;

  /**
   * 用来获取当前Context
   */
  private Activity activity;

  /**
   *
   */
  private Thread thread;

  /**
   * 入口方法
   */
  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    //初始化MethodChannel，与flutter MethodChannel('yc_plugin_learn')传入相同的字符串，大家在一个通道上
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "yc_plugin_learn");
    channel.setMethodCallHandler(this);

    //初始化事件通道，主要是获取这个EventChannel.EventSink sink，用这个sink发消息给flutter
    new EventChannel(flutterPluginBinding.getBinaryMessenger(), "yc_plugin_learn_eventChannel").setStreamHandler(new EventChannel.StreamHandler() {
      @Override
      public void onListen(Object o, EventChannel.EventSink eventSink) {
        sink = eventSink;
      }

      @Override
      public void onCancel(Object o) {
        sink = null;
      }
    });


    //这儿演示flutter加载原生view
    //注册PlatformViewFactory，用于展示原生view。在flutter中UiKitView显示viewType: "YcPluginLearnPlugin.testView",在这个位置
    YcPlatformViewFactory ycPlatformViewFactory = new YcPlatformViewFactory(StandardMessageCodec.INSTANCE,flutterPluginBinding);
    flutterPluginBinding.getPlatformViewRegistry().registerViewFactory("YcPluginLearnPlugin.testView",ycPlatformViewFactory);

  }


  /**
   * flutter触发
   */
  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else if (call.method.equals("getImage")) {
      getImageHandler(call, result);
    } else if (call.method.equals("init")) {

      //接收到的数据
      HashMap argumentsMap = (HashMap) call.arguments;
      String appId = argumentsMap.get("appId").toString();
      System.out.println("原生：" + appId);

      HashMap<String, String> map = new HashMap<>();
      map.put("code", "1");
      map.put("msg","success");

      result.success(map);
      //result.error();

    } else if (call.method.equals("appList")) {
      /**
       * 获取手机安装的app,及包名
       */

      //子线程耗时操作
      thread = new Thread(new Runnable() {
        @Override
        public void run() {
          System.out.println("打出一下 appList");
          Context context = activity.getApplicationContext();
          PackageManager manager = context.getPackageManager();
          List<PackageInfo> packageInfos = manager.getInstalledPackages(0);

          ArrayList<String> list = new ArrayList<>();
          for (PackageInfo pi : packageInfos) {
            try {
              ApplicationInfo appInfo = manager.getApplicationInfo(pi.packageName, 0);
              CharSequence applicationLabel = manager.getApplicationLabel(appInfo);
              //System.out.println("appInfo ===== " + applicationLabel+ " pi.packageName = " + pi.packageName);
              list.add(pi.packageName);
            } catch (PackageManager.NameNotFoundException e) {
              e.printStackTrace();
            }
          }
          System.out.println("打出一下 " + list.size());
          HashMap<String, Object> map = new HashMap<>();
          map.put("type", "2");
          map.put("list", list);
          System.out.println("打出一下 " + map.toString());

          //回到主线程
          if(activity != null){
            activity.runOnUiThread(new Runnable() {
              @Override
              public void run() {
                if (sink != null)
                  sink.success(map);
              }
            });
          }
        }
      });
      thread.start();


      //result.success(list);

    } else if (call.method.equals("launchApp")) {
      /**
       * 启动apk
       */
      HashMap argumentsMap = (HashMap) call.arguments;
      String packageName = argumentsMap.get("packageName").toString();
      Context context = activity.getApplicationContext();
      Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
      context.startActivity(intent);

      HashMap<String, String> map = new HashMap<>();
      map.put("code", "1");
      map.put("msg","success");
      result.success(map);

    } else if (call.method.equals("unInstallApp")) {
      /**
       * 卸载apk
       */
      HashMap argumentsMap = (HashMap) call.arguments;
      String packageName = argumentsMap.get("packageName").toString();
      Intent intent = new Intent(Intent.ACTION_DELETE);
      intent.setData(Uri.parse("package:" + packageName));
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      Context context = activity.getApplicationContext();
      context.startActivity(intent);

    }
    else if (call.method.equals("test")) {
      //测试，给flutter不停地发消息
      for (int i=0;i<20000;i++){
        //不停地回调给原生
        HashMap<String, String> map = new HashMap<>();
        map.put("type", "0");
        map.put("second","" + i);

        sink.success(map);
      }
    }else if (call.method.equals("installApp")) {
      Context context = activity.getApplicationContext();
      HashMap argumentsMap = (HashMap) call.arguments;
      String appId = argumentsMap.get("appId").toString();
      String path = argumentsMap.get("file").toString();
      File file = new File(path);


      Intent intent = new Intent(Intent.ACTION_VIEW);
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      Uri uri = FileProvider.getUriForFile(context, appId + ".fileProvider.install", file);
      intent.setDataAndType(uri, "application/vnd.android.package-archive");
      context.startActivity(intent);
    }else if (call.method.equals("storagePath")) {
      File file = Environment.getExternalStorageDirectory();
      result.success(file.getAbsolutePath());
    }

    else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }


  /**
   * 加载图片
   * 使用Glide进行网络图片的下载和缓存，需要在build.gradle(Module:android.yc_plugin_learn)文件中声明依赖，
   */
  public void getImageHandler(final MethodCall call,final Result result){
    Context applicationContext = activity.getApplicationContext();
    HashMap map = (HashMap) call.arguments;
    String urlStr = map.get("url").toString();
    Uri uri = Uri.parse(urlStr);
    if("localImage".equals(uri.getScheme())){
      String imageName = uri.getHost();
      int lastIndex = imageName.lastIndexOf(".");
      if(lastIndex > 0){
        imageName = imageName.substring(0,lastIndex);
      }
      String imageUri = "@drawable/"+imageName;
      int imageResource = applicationContext.getResources().getIdentifier(imageUri, null, applicationContext.getPackageName());
      if(imageResource > 0){
        Bitmap bmp = BitmapFactory.decodeResource(applicationContext.getResources(),imageResource);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] byteArray = stream.toByteArray();
        result.success(byteArray);
      }else{
        result.error("NOT_FOUND","file not found",call.arguments);
      }
    }else {
      Glide.with(applicationContext).download(urlStr).into(new CustomTarget<File>() {
        @Override
        public void onResourceReady(@NonNull File resource, @Nullable Transition<? super File> transition) {
          byte[] bytesArray = new byte[(int) resource.length()];
          try {
            FileInputStream fis = new FileInputStream(resource);
            fis.read(bytesArray);
            fis.close();
            result.success(bytesArray);
          } catch (IOException e) {
            e.printStackTrace();
            result.error("READ_FAIL",e.toString(),call.arguments);
          }
        }
        @Override
        public void onLoadFailed(@Nullable Drawable errorDrawable) {
          super.onLoadFailed(errorDrawable);
          result.error("LOAD_FAIL","image download fail",call.arguments);
        }
        @Override
        public void onLoadCleared(@Nullable Drawable placeholder) {
          result.error("LOAD_CLEARED","image load clear",call.arguments);
        }
      });
    }
  }


  /**
   * ActivityAware 用来获取Context applicationContext = activity.getApplicationContext()
   */
  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    activity = binding.getActivity();
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
    this.onDetachedFromActivity();
  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
    this.onAttachedToActivity(binding);
  }

  @Override
  public void onDetachedFromActivity() {
    activity = null;
  }
}
